package com.lagou.edu.factory;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.reflections.Reflections;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BeanFactory {
    // 存储管理对象
    private static Map<String, Object> map = new HashMap<>();

    static {
        // 使用反射获取包下的所有类
        Reflections reflection = new Reflections("com.lagou.edu");
        Set<Class<?>> classSet = reflection.getTypesAnnotatedWith(Service.class);

        for (Class<?> clazz : classSet) {
            // 获取实例化对象
            Object object = null;
            try {
                object = clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            Service service = clazz.getAnnotation(Service.class);

            if (StringUtils.isEmpty(service.name())) {
                String[] names = clazz.getName().split("\\.");
                map.put(names[names.length - 1], object);
            } else {
                map.put(service.name(), object);
            }
        }
        //维护对象之间依赖关系
        for (Map.Entry<String, Object> entrySet : map.entrySet()) {
            Object obj = entrySet.getValue();
            Class clazz = obj.getClass();
            //获取每个类的所有属性
            Field[] fields = clazz.getDeclaredFields();
            // 遍历属性，确认是否有使用Autowired注解，有使用注解则需要完成注入
            for (Field field : fields) {
                //判断是否使用注解的参数
                if (field.isAnnotationPresent(Autowired.class) && field.getAnnotation(Autowired.class).required()) {
                    String[] names = field.getType().getName().split("\\.");
                    String name = names[names.length - 1];
                    Method[] methods = clazz.getMethods();
                    for (int j = 0; j < methods.length; j++) {
                        Method method = methods[j];
                        if (method.getName().equalsIgnoreCase("set" + name)) {
                            try {
                                method.invoke(obj, map.get(name));
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            // 遍历方法，确认是否有Transactional注解
            for (Method declaredMethod : clazz.getDeclaredMethods()) {
                if (declaredMethod.getAnnotation(Transactional.class) != null) {
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    Class[] face = clazz.getInterfaces();
                    //判断对象是否实现接口
                    if (face != null && face.length > 0) {
                        //有实现接口，使用JDK
                        obj = proxyFactory.getJdkProxy(obj);
                    } else {
                        //没有实现接口，使用CGLIB
                        obj = proxyFactory.getCglibProxy(obj);
                    }
                }
            }
            map.put(entrySet.getKey(), obj);
        }
    }

    public static Object getBean(String id) {
        return map.get(id);
    }

}
